function Game(ROW_NUM, COLUMN_NUM, ele = '.game_box') {
    this.ROW_NUM = ROW_NUM;
    this.COLUMN_NUM = COLUMN_NUM;
    this.container = document.querySelector(ele);
    this.score = document.querySelector('span#score');
    this.bindEvent()
    this.init();
    this.start()
}

let fn = Game.prototype;
fn.init = function () {

    this.snake = [{x: this.COLUMN_NUM / 2, y: this.ROW_NUM / 2}];
    this.currentArrow = this.down;

    this.makeFood();
    this.DataArray();
    this.renderView()
};

fn.top = 1;
fn.right = 2;
fn.down = 3;
fn.left = 4;

fn.bindEvent = function () {
    var _this = this;
    document.addEventListener('keydown', function (event) {
        if (event.keyCode === 39) {
            //right
            if (_this.currentArrow !== _this.left) {
                _this.currentArrow = _this.right;
            }
        } else if (event.keyCode === 40) {
            //down
            if (_this.currentArrow !== _this.top) {
                _this.currentArrow = _this.down;
            }
        } else if (event.keyCode === 37) {
            //left
            if (_this.currentArrow !== _this.right) {
                _this.currentArrow = _this.left
            }
        } else if (event.keyCode === 38) {
            //top
            if (_this.currentArrow !== _this.down) {
                _this.currentArrow = _this.top;
            }
        } else if (event.keyCode === 13) {
            if (!_this.gameFlag) {
                _this.init()
                _this.start()
            }
        }
    })
};

fn.moveData = function () {
    //先将头部复制出一份，向前移动
    this.snake.unshift(JSON.parse(JSON.stringify(this.snake[0])))
    this.snake.pop()
    var nextPoint;
    //对蛇头的新位置做判断
    switch (this.currentArrow) {
        case this.left:
            nextPoint = {x: this.snake[0].x - 1, y: this.snake[0].y};
            break;
        case this.down:
            nextPoint = {x: this.snake[0].x, y: this.snake[0].y + 1};
            break;
        case this.right:
            nextPoint = {x: this.snake[0].x + 1, y: this.snake[0].y};
            break;
        case this.top:
            nextPoint = {x: this.snake[0].x, y: this.snake[0].y - 1};
            break;
    }

    if (this.checkPoint(nextPoint, this.snake)) {
        console.log('eat self')
        this.stop();
        return
    }

    if (nextPoint.x < 0 || nextPoint.x > this.COLUMN_NUM || this.snake[0].y < 0 || this.snake[0].y > this.ROW_NUM) {
        console.log('out')
        this.stop();
        return
    }

    if (this.checkPoint(nextPoint, [this.food])) {
        this.eat();
    } else {
        this.snake[0] = nextPoint;
    }
};
fn.moveRender = function () {
    this.moveData()
    this.DataArray();
    this.renderView()
};

fn.eat = function () {
    this.snake.push({x: this.food.x, y: this.food.y})
    this.makeFood();
};

fn.start = function () {
    this.gameFlag = setInterval(() => {
        game.moveRender();
    }, 100)
};

fn.stop = function () {
    clearInterval(this.gameFlag);
    this.gameFlag = null;
    alert('game over')
};


fn.DataArray = function () {
    this.data = [];
    let i = 0, j = 0;
    for (; i < this.ROW_NUM; i++) {
        var cache = [];
        for (; j < this.COLUMN_NUM; j++) {
            var status = 2
            if (this.checkPoint({x: j, y: i}, this.snake)) {
                status = 1
            }
            if (this.checkPoint({x: j, y: i}, [this.food])) {
                status = 3
            }

            cache.push(status);
        }
        j = 0;
        this.data.push(cache)
    }
};

fn.renderView = function () {
    var fragment = document.createDocumentFragment();
    this.data.forEach((x) => {
        x.forEach((x) => {
            var ele = document.createElement('div');
            if (x === 1) {
                ele.setAttribute('data-null', '')
            } else if (x === 2) {
                ele.setAttribute('data-food', '')
            } else if (x === 3) {
                ele.setAttribute('data-snake', '')
            }
            fragment.appendChild(ele)
        })
    });
    this.container.innerHTML = '';
    this.container.appendChild(fragment)
};

fn.makeFood = function () {
    this.score.innerHTML = this.snake.length
    var randCur = Math.ceil(Math.random() * this.ROW_NUM * this.COLUMN_NUM)
    var point = this.indexToPoint(randCur);
    var rand = randCur, step = 1;
    while (this.checkPoint(point, this.snake)) {
        rand += step;
        if (rand > this.COLUMN_NUM * this.ROW_NUM) {
            rand = randCur;
            step = -1
        }
        point = this.indexToPoint(rand);
    }
    console.log(point)
    this.food = point
};

fn.checkPoint = function (point, objArray) {
    objArray = objArray.constructor === [].constructor ? objArray : objArray
    return objArray.some(function (x) {
        return (x.x === point.x && x.y === point.y)
    })
};

fn.indexToPoint = function (index) {
    return {
        y: Math.ceil(index / this.COLUMN_NUM),
        x: index % this.COLUMN_NUM
    };
};
let game = new Game(60, 60);
